package com.fancy.middleware.common.config;

import com.fancy.middleware.common.beans.DomainWrapper;
import com.fancy.middleware.common.handler.disruptor.DomainEventHandler;
import com.fancy.middleware.common.product.FrameDataEventProducer;
import com.fancy.middleware.common.properties.DisruptorProperties;
import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.WaitStrategy;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import com.lmax.disruptor.util.DaemonThreadFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Disruptor.class)
@EnableConfigurationProperties(DisruptorProperties.class)
public class DisruptorAutoConfiguration {

    @Autowired
    private DisruptorProperties properties;

    @Bean
    @ConditionalOnMissingBean
    public WaitStrategy waitStrategy() {
        return new YieldingWaitStrategy();
    }

    @Bean
    @ConditionalOnMissingBean
    public EventFactory<DomainWrapper> eventFactory() {
        return () -> new DomainWrapper();
    }

    @Bean
    @ConditionalOnMissingBean
    public RingBuffer<DomainWrapper> ringBuffer(@Autowired EventFactory<DomainWrapper> factory,
                                                @Autowired WaitStrategy waitStrategy) {
        int bufferSize = properties.getBufferSize();
        Disruptor<DomainWrapper> disruptor = new Disruptor<>(factory,
                bufferSize,
                DaemonThreadFactory.INSTANCE,
                ProducerType.MULTI,
                waitStrategy);
        // TODO Modify 设置 事件处理器 可以使用门面模式包装下
        disruptor.handleEventsWith(new DomainEventHandler());
        disruptor.start();
        return disruptor.getRingBuffer();
    }

    @Bean
    @ConditionalOnMissingBean
    public FrameDataEventProducer<DomainWrapper> frameDataEventProducer(@Autowired RingBuffer<DomainWrapper> ringBuffer) {
        return new FrameDataEventProducer(ringBuffer);
    }





}
